﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using Lib.Helper;
using MSIACCSL2.CoaServices;
using MSIACCSL2.Command;
using MSIACCSL2.Struct;
using MSIACCSL2.Views.COA;
using WcfService1.DTO;
using GetListByCriteriaCompletedEventArgs = MSIACCSL2.CoaServices.GetListByCriteriaCompletedEventArgs;
using GetListCompletedEventArgs = MSIACCSL2.CoaServices.GetListCompletedEventArgs;
using SaveCompletedEventArgs = MSIACCSL2.CoaServices.SaveCompletedEventArgs;

namespace MSIACCSL2.ViewModels
{
    public class COAViewModel : ViewModelBase
    {
        #region Delegates

        public delegate void Completed(Object param);

        #endregion

        private static string OrderType;
        private static string PropertySort;
        public static Mode mode;
        private static CoaDTO _COA;
        private static Add frmAdd;
        public static Completed OnSearchCompleted;
        private readonly CoaServicesClient client;
        private readonly ValidationHandler validationHandler;
        private int CurrentPage;
        private ObservableCollection<int> Pages;
        private PagedCollectionView _COAs;
        private bool _IsBusy;
        private ObservableCollection<string> _categories;
        private List<string> _errors;
        private Visibility _messageVisibility;
        private PagedCollectionView _pageSources;
        private ObservableCollection<CoaDTO> _parents;
        private static Search frmSearch;
        private ObservableCollection<string> _Infos;
        private ObservableCollection<SaldoAwalPiutang> _SaldoAwalPiutangs;
        private ObservableCollection<SaldoAwalHutang> _SaldoAwalHutangs;


        public COAViewModel()
        {
            if (!DesignerProperties.IsInDesignTool)
            {
                client = new CoaServicesClient();
                OnPageChanged = new DelegateCommand(PageIndexChanged, CanPageIndexChanged);
                Save = new DelegateCommand(SaveCOA, CanSave);
                New = new DelegateCommand(NewCOA, CanNew);
                Edit = new DelegateCommand(EditCOA, CanEdit);
                Unload = new DelegateCommand(Release, CanUnload);
                SearchCommand = new DelegateCommand(SearchCOA, CanSearch);
                SearchResultCommand = new DelegateCommand(SearchResult, CanSearchResult);
                validationHandler = new ValidationHandler();
                MessageVisibility = Visibility.Collapsed;


                if (mode == Mode.Edit || mode == Mode.Search || mode == Mode.Add)
                {
                    GetAllParentCOA();
                    LoadCateGory();
                    LoadGeneralInfo();
                }
                else
                {
                    GetList(1, null);
                }
            }
        }

        public PagedCollectionView COAs
        {
            get { return _COAs; }

            private set
            {
                if (COAs == value) return;
                _COAs = value;
                int i = (CurrentPage*30);
                foreach (object COA in COAs)
                {
                    i += 1;

                    ((CoaDTO) COA).No = i;
                }
                FirePropertyChanged("COAs");
                COAs.CollectionChanged += COA_CollectionChanged;
            }
        }


        public PagedCollectionView PageSources
        {
            get { return _pageSources; }
            private set
            {
                if (PageSources == value) return;
                _pageSources = value;
                FirePropertyChanged("PageSources");
            }
        }

        public ObservableCollection<CoaDTO> ParentCOAs
        {
            get { return _parents; }
            private set
            {
                if (ParentCOAs == value) return;
                _parents = value;
                FirePropertyChanged("ParentCOAs");
            }
        }


        public bool IsBusy
        {
            get { return _IsBusy; }
            internal set
            {
                _IsBusy = value;
                FirePropertyChanged("IsBusy");
            }
        }


        public long RecordCount { get; set; }

        //Buat binding ke child form waktu mau edit
        public static CoaDTO COA
        {
            get { return _COA; }
            private set
            {
                if (COA == value) return;
                _COA = value;
                FirePropertyChanged2("COA");
            }
        }


        public ICommand OnPageChanged { get; set; }
        public ICommand Save { get; set; }
        public ICommand New { get; set; }
        public ICommand Edit { get; set; }
        public ICommand Unload { get; set; }
        public ICommand SearchCommand { get; set; }
        public ICommand SearchResultCommand { get; set; }

        public List<string> Errors
        {
            get { return _errors; }
            private set
            {
                if (Errors == value) return;
                _errors = value;
                FirePropertyChanged("Errors");
            }
        }

        public ObservableCollection<string> Categories
        {
            get { return _categories; }
            private set
            {
                if (Categories == value) return;
                _categories = value;
                FirePropertyChanged("Categories");
            }
        }

        public ObservableCollection<string> Infos
        {
            get { return _Infos; }
            private set
            {
                if (Infos == value) return;
                _Infos = value;
                FirePropertyChanged("Infos");
            }
        }

        public Visibility MessageVisibility
        {
            get { return _messageVisibility; }
            private set
            {
                if (MessageVisibility == value) return;
                _messageVisibility = value;
                FirePropertyChanged("MessageVisibility");
            }
        }

        public string this[string columnName]
        {
            get
            {
                if (validationHandler.BrokenRuleExists(columnName))
                {
                    return validationHandler[columnName];
                }
                return null;
            }
        }

        private void LoadCateGory()
        {
            Categories = new ObservableCollection<string>();
            Categories.Add(AccountType.Assets.ToString());
            Categories.Add(AccountType.Liability.ToString());
            Categories.Add(AccountType.Equity.ToString());
            Categories.Add(AccountType.Income.ToString());
            Categories.Add(AccountType.COGS.ToString());
            Categories.Add(AccountType.Expense.ToString());
            Categories.Add(AccountType.OtherIncome.ToString());
            Categories.Add(AccountType.OtherExpense.ToString());
        }

        private void LoadGeneralInfo()
        {
            Infos = new ObservableCollection<string>();
            Infos.Add(null);
            Infos.Add("Kas & Bank");
            Infos.Add("Laba Bulan Berjalan");
            Infos.Add("Inventory");
            Infos.Add("Sales");
            Infos.Add("SalesReturn");
            Infos.Add("Cogs");
            Infos.Add("Expense");
            Infos.Add("Piutang Usaha");
            Infos.Add("Piutang Lain-lain");
            Infos.Add("Piutang Karyawan");
            Infos.Add("Aktiva Tetap");
            Infos.Add("Hutang Jangka Panjang");
            Infos.Add("Hutang Usaha");
            Infos.Add("Hutang Lain-lain");
        }

        public void Complete(Object param)
        {
            OnSearchCompleted(param);
        }

        private void COA_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (((PagedCollectionView) sender).SortDescriptions.Count > 0)
            {
                if (((PagedCollectionView) sender).SortDescriptions[0].PropertyName.ToLower() == "no") return;

                PropertySort = ((PagedCollectionView) sender).SortDescriptions[0].PropertyName;
                if (string.IsNullOrEmpty(OrderType))
                {
                    OrderType = "ASC";
                }
                else
                {
                    OrderType = OrderType == "ASC" ? OrderType = "DESC" : OrderType = "ASC";
                }
                GetList(1, PropertySort);
            }
        }


        public void SaveCOA(Object coa)
        {
            Validate();
            if (Errors.Count > 0) return;
            COA.created_by = GlobalVar.User.UserID;
            COA.modified_by = GlobalVar.User.UserID;
            client.SaveCompleted += client_SaveCOACompleted;
            client.SaveAsync(COA);
            frmAdd.DialogResult = true;
        }


        private void client_SaveCOACompleted(object sender, SaveCompletedEventArgs e)
        {
            if (e.Error != null) Validate(e.Error.ToString());
            client.SaveCompleted -= client_SaveCOACompleted;
            if (e.Result)
            {
                MessageBox.Show("Success");
                Refresh();
            }
        }


        public void GetList(int? page, string sortProp)
        {
            IsBusy = true;
            client.GetListCompleted += client_GetListCompleted;
            client.GetListAsync(page ?? 1, sortProp, OrderType);
        }

        private void client_GetListCompleted(object sender, GetListCompletedEventArgs e)
        {
            RecordCount = e.recordCount;
            if (PageSources == null) CreatePageNumber();
            client.GetListCompleted -= client_GetListCompleted;
            COAs = new PagedCollectionView(e.Result);
            IsBusy = false;
            Complete(this);
        }


        private void NewCOA(Object param)
        {
            mode = Mode.Add;
            COA = new CoaDTO();
            frmAdd = new Add();
            frmAdd.Show();
        }


        public static void EditCOA(Object param)
        {
            mode = Mode.Edit;
            COA = (CoaDTO) param;
            frmAdd = new Add();
            frmAdd.Show();
        }


        private void SearchCOA(Object param)
        {
            COA = new CoaDTO();
            mode = Mode.Search;
            frmSearch = new Search();
            frmSearch.Show();
        }


        private void SearchResult(Object param)
        {
       
            var criteria = new Dictionary<string, object>();
            foreach (PropertyInfo prop in COA.GetType().GetProperties())
            {
                if (prop.PropertyType == typeof (Decimal))
                {
                    if ((Decimal) prop.GetValue(COA, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (Int32))
                {
                    if ((Int32) prop.GetValue(COA, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (Int64))
                {
                    if ((Int64) prop.GetValue(COA, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (Double))
                {
                    if ((Double) prop.GetValue(COA, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (String))
                {
                    if (String.IsNullOrEmpty((String) prop.GetValue(COA, null))) continue;
                }
                if (prop.PropertyType == typeof (DateTime))
                {
                    if (prop.GetValue(COA, null).ToString().Contains("0001")) continue;
                }
                if (prop.GetValue(COA, null) == null) continue;
                if (prop.PropertyType.Name == "No") continue;

                if (prop.PropertyType.Name.ToLower().Contains("dto"))
                {
                    foreach (PropertyInfo propertyInfo in prop.GetValue(COA, null).GetType().GetProperties())
                    {
                        if (propertyInfo.Name.ToLower().Contains("id") || propertyInfo.Name.ToLower().Contains("kode") ||
                            propertyInfo.Name.ToLower().Contains("serial") ||
                            propertyInfo.Name.ToLower().Contains("code"))
                        {
                            criteria.Add(prop.Name, propertyInfo.GetValue(prop.GetValue(COA, null), null));
                            break;
                        }
                    }
                }
                else
                {
                    criteria.Add(prop.Name, prop.GetValue(COA, null));
                }
            }

            string expression = string.Empty;
            if (frmSearch.rbOr.IsChecked ?? false) expression = "OR";
            else expression = "AND";
            COASearch(criteria, expression);
        }

        private void COASearch(Dictionary<String, Object> criteria, string expression)
        {
            frmSearch.DialogResult = true;
            IsBusy = true;
            Complete(this);
            client.GetListByCriteriaCompleted += client_GetListByCriteriaCompleted;
            client.GetListByCriteriaAsync(criteria, expression, 1);
        }

        private void client_GetListByCriteriaCompleted(object sender, GetListByCriteriaCompletedEventArgs e)
        {
            client.GetListByCriteriaCompleted -= client_GetListByCriteriaCompleted;
            COAs = new PagedCollectionView(e.Result);
            RecordCount = e.recordCount;
            CreatePageNumber();
            IsBusy = false;
        }

        private void GetAllParentCOA()
        {
            client.GetAllCoaCompleted += client_GetListByCriteriaCompleted2;
            client.GetAllCoaAsync();
        }

        private void client_GetListByCriteriaCompleted2(object sender, GetAllCoaCompletedEventArgs e)
        {
            client.GetAllCoaCompleted -= client_GetListByCriteriaCompleted2;
            ParentCOAs = e.Result;
            if (COA != null && COA.ParentAccount != null)
                COA.ParentAccount = ParentCOAs.FirstOrDefault(m => m == COA.ParentAccount);
           
        }

        private void CreatePageNumber()
        {
            Pages = new ObservableCollection<int>();
            for (int i = 0; i < RecordCount; i++)
            {
                Pages.Add(i);
            }
            PageSources = new PagedCollectionView(Pages);
        }


        private void PageIndexChanged(Object pageIndex)
        {
            //Jika Pertama kali jangan di Getlagi
            COA = null;
            if (COAs != null && CurrentPage != (int) pageIndex)
            {
                CurrentPage = (int) pageIndex;
                if (String.IsNullOrEmpty(PropertySort))
                    GetList((int) pageIndex + 1, null);
                else GetList((int) pageIndex + 1, PropertySort);
            }
        }


        public bool CanPageIndexChanged(Object param)
        {
            return true;
        }


        public bool CanSave(Object param)
        {
            return true;
        }


        public bool CanNew(Object param)
        {
            return true;
        }

        public bool CanEdit(Object param)
        {
            return true;
        }


        public bool CanUnload(Object param)
        {
            return true;
        }


        public bool CanSearch(Object param)
        {
            return true;
        }

        public bool CanSearchResult(Object param)
        {
            return true;
        }


        public void Release(Object param)
        {
            param = null;
            COA = null;
            OrderType = null;
            PropertySort = null;
            mode = Mode.Idle;
        }


        public void Refresh()
        {
            if (COAs == null)
                GetList(1, null);
            else
                Complete(this);
        }


        public void Validate(string error = null)
        {
            Errors = new List<string>();
            if (string.IsNullOrEmpty(COA.AccountNumber))
                Errors.Add("COAname tidak boleh kosong");
            if (!string.IsNullOrEmpty(error))
                Errors.Add(error);

            if (Errors.Count > 0)
            {
                MessageVisibility = Visibility.Visible;
            }
            else
            {
                MessageVisibility = Visibility.Collapsed;
            }
        }


        public void GetSaldoAwalHutang()
        {
            client.GetMutasiHutangCompleted += client_GetMutasiHutangCompleted;
            client.GetMutasiHutangAsync(COA.AccountNumber);
        }

        void client_GetMutasiHutangCompleted(object sender, GetMutasiHutangCompletedEventArgs e)
        {
            client.GetMutasiHutangCompleted -= client_GetMutasiHutangCompleted;
            EventAggregator.PublishMessage("ShowDetailSaldoHutang",COA,e.Result);
           

            //if (e.Result.Count > 0)
            //    detail.ViewModel.SaldoAwalHutangs = e.Result;
        }

        public void GetSaldoAwalPiutang()
        {
            client.GetMutasiPiutangCompleted += client_GetMutasiPiutangCompleted;
            client.GetMutasiPiutangAsync(COA.AccountNumber);
        }

        void client_GetMutasiPiutangCompleted(object sender, GetMutasiPiutangCompletedEventArgs e)
        {
            client.GetMutasiPiutangCompleted -= client_GetMutasiPiutangCompleted;
            var detail = new DetailSaldoPiutang();
            detail.DataContext = new SaldoPiutangViewModel(COA);
            detail.Show();

            if (e.Result.Count > 0)
                detail.ViewModel.SaldoAwalPiutangs = e.Result;
        }

     
    }


    public class COAWrapViewModel : ViewModelBase
    {
        private readonly CoaServicesClient client;

        public COAWrapViewModel()
        {
            if (!DesignerProperties.IsInDesignTool)
            {
                EditCommand = new DelegateCommand(Edit, CanEditCommand);
                DeleteCommand = new DelegateCommand(Delete, CanDeleteCommand);
                client = new CoaServicesClient();
            }
        }


        public ICommand EditCommand { get; set; }
        public ICommand DeleteCommand { get; set; }


        public bool CanEditCommand(Object param)
        {
            return true;
        }

        public bool CanDeleteCommand(Object param)
        {
            return true;
        }


        public void Edit(Object param)
        {
            COAViewModel.EditCOA(param);
        }

        public void Delete(Object param)
        {
            client.DeleteCompleted += client_DeleteCompleted;
            client.DeleteAsync((CoaDTO) param);
        }

        private void client_DeleteCompleted(object sender, AsyncCompletedEventArgs e)
        {
            client.DeleteCompleted -= client_DeleteCompleted;
            MessageBox.Show("Delete Success!");
            COAViewModel.mode = Mode.Idle;
            var VM = new COAViewModel();
        }
    }


    public class CurrencyConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null) return string.Empty;
            return ((dynamic) value).CurrencyCode;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    public class COAConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null) return string.Empty;
            return ((dynamic)value).AccountNumber + ":" + ((dynamic)value).AccountName;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }


    
}